home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-10-31 | 11.8 KB | 392 lines | [TEXT/MPS ] |
- ;
- ; Apple Macintosh Developer Technical Support
- ;
- ; Exception handling for MPW Pascal, MacApp and MPW C
- ;
- ; UFailure (aka Signals) - “Exceptional code, with a few exceptions.”
- ;
- ; UFailure.a - Assembly Source
- ;
- ; Copyright © 1985-1988 Apple Computer, Inc.
- ; All rights reserved.
- ;
- ; Versions: 1.0 11/88
- ;
- ; Components: UFailure.p November 1, 1988
- ; UFailure.h November 1, 1988
- ; UFailure.inc1.p November 1, 1988
- ; UFailure.a November 1, 1988
- ; TestCignal.c November 1, 1988
- ; TestCignal.make November 1, 1988
- ; TestSignal.p November 1, 1988
- ; TestSignal.make November 1, 1988
- ;
- ; UFailure (or Signals) is a set of exception handling routines suitable for
- ; use with MacApp, MPW C, and MPW Pascal. It is a jazzed-up version of the MacApp
- ; UFailure unit. There is a set of C interfaces to it as well.
- ;
-
- PRINT OFF
- INCLUDE 'Traps.a'
- PRINT ON
-
- STRING ASIS
-
- ;=============================================================================================
- GblA &UsingMacApp
- If &TYPE('&Debugging') = 'UNDEFINED' Then
- GblA &Debugging
- &UsingMacApp SetA 0 ; we assume we’re MacAppless if &Debugging isn’t defined
- If &TYPE('&Debug') = 'UNDEFINED' Then
- &Debugging SetA 0 ; default to debugging off
- Else
- &Debugging SetA &Debug ; use the makefile definition of &Debug
- EndIf
- Else
- &UsingMacApp SetA 1 ; we assume we have MA if &Debugging is defined
- EndIf
- ;=============================================================================================
- If &TYPE('Head') = 'UNDEFINED' Then
- Macro
- Head
- GblA &Debugging
- If &Debugging Then
- Link A6,#0 ; These two instructions form a slow no-op
- Move.L (SP)+,A6
- EndIf
- EndM
- EndIf
- ;=============================================================================================
- If &TYPE('Tail') = 'UNDEFINED' Then
- Macro
- Tail
- GblA &Debugging
- If &Debugging Then
- Unlk A6
- Rts
- DC.B &Ord(&SubStr(&Syslst[1],2,1)) + $80
- DC.B '&SubStr(&Syslst[1],3,7)'
- EndIf
- EndM
- EndIf
- ;=============================================================================================
-
- ; the following constant sets the limit on the depth of nested CatchSignals
- SigBlockSize EQU 8 ;number of elements in block
-
- CatchSigErr EQU 200 ;"insufficient heap" message
- SigElSize EQU 72 ;byte size of FailInfo record
- FrameRet EQU 4 ;return addr. for frame (off A6)
- SigBigA6 EQU $FFFFFFFF ;A6 at outer level (for Pascal)
- nSavedRegs EQU 11 ;number of registers saved in FailInfo record
-
- ; offsets into the FailInfo record (see UFailure.p)
- SigA6 EQU 36
- SigSP EQU 40
- SigCode EQU 44
- SigMessage EQU 46
- SigFailA6 EQU 50
- SigFailPC EQU 54
- whatSignals EQU 66
- SigFRet EQU 68
-
-
- ; The global data used by these routines follows. It is in the form of a
- ; RECORD, but, unlike above, no origin is specified, which means that memory
- ; space *will* be allocated.
- ; This data is referenced through a WITH statement at the beginning of the
- ; procs that need to get at this data. Since the Assembler knows when it is
- ; referencing data in a data module (since they must be declared before they
- ; are accessed), and since such data can only be accessed based on A5, there
- ; is no need to explicitly specify A5 in any code which references the data
- ; (unless indexing is used). Thus, in this program we have omitted all A5
- ; references when referencing the data.
-
- SigGlobals RECORD ;no origin means this is a data record
- ;not a template(as above)
- SigEnd DS.L 1 ;current end of table
- SigNow DS.L 1 ;the current offset
- SigPointer DC.L 0 ;the handle := 0 initially
- ENDR
-
-
- If &UsingMacApp Then
- Seg 'MAInit'
- EndIf
- InitSignals PROC EXPORT ;PROCEDURE InitSignals;
- EXPORT InitUFailure
- IMPORT gTopHandler:Data
- IMPORT gInitHandler:Data
- If &UsingMacApp And &Debugging Then
- IMPORT gAskAboutAlloc:Data
- IMPORT gAskFailure:Data
- EndIf
- WITH SigGlobals
- ;the above statement makes the template SigElement and the global data
- ;record SigGlobals available to this procedure
-
- Head
- MOVE.L #SigBigA6,A6 ;make A6 valid for Signal
- InitUFailure ;PROCEDURE InitUFailure;
- CLR.L gTopHandler(A5) ;nothing in the list
- CLR.L gInitHandler(A5) ;MA has another list during initialization
- If &UsingMacApp And &Debugging Then
- CLR.B gAskAboutAlloc(A5) ;set the MA debugging guys to FALSE
- CLR.B gAskFailure(A5)
- EndIf
-
- MOVE.L #SigBlockSize*SigElSize,D0
- _NewPtr ;try to get a table
- BNE.S forgetit ;we couldn't get that!?
-
- MOVE.L A0,SigPointer ;save it
- MOVE.L #-SigElSize,SigNow ;point "now" before start
- MOVE.L #SigBlockSize*SigElSize,SigEnd ;save the end
- forgetit RTS
-
- Tail 'INITUFAI'
- ENDP
-
-
- If &UsingMacApp Then
- Seg 'MAMain'
- EndIf
- CatchCFailures PROC EXPORT ;pascal void CatchCFailures(FailInfo &fi, HandlerFuncPtr handler);
- IMPORT FailCEntry
-
- Head
- MOVE.L (A7)+,D2 ;save return address
- MOVEQ #0,D1 ;CatchCFailures used (no A6 link, uses handler proc.)
- BRA.S FailCEntry ;finish from CatchFailures
- Tail 'CATCHCFA'
-
- CatchFailures PROC EXPORT ;PROCEDURE CatchFailures(VAR fi: FailInfo;
- ; PROCEDURE Handler(code: INTEGER; message: LONGINT));
- IMPORT FailuresEntry
- EXPORT FailCEntry
- WITH SigGlobals
-
- Head
- MOVE.L (A7)+,D2 ;save return address
- ADDQ #4,A7 ;discard A6 link
- MOVEQ #-1,D1 ;CatchFailures used (maybe A6 link???, handler proc.)
- FailCEntry
- MOVE.L (A7)+,A1 ;get handler address
- MOVE.L (A7)+,A0 ;FailInfo record address
- BRA.S FailuresEntry ;enter CatchSignal with D2, A0, A1 set
- Tail 'CATCHFAI'
-
- CatchSignal PROC EXPORT ;FUNCTION CatchSignal:INTEGER
- IMPORT SiggyPop2,Signal,SigDeath
- IMPORT gTopHandler:Data
- EXPORT FailuresEntry
- WITH SigGlobals
-
- Head
- MOVE.L (A7)+,A1 ;grab return address for “handler” address
- MOVE.L A1,D2 ;save return address
- MOVEQ #1,D1 ;CatchSignals used; no A6 link needed on stack, no proc.
- CLR.W (A7) ;no error code (before its time)
-
- MOVE.L SigPointer,D0 ;point to table
- BEQ SigDeath
- MOVE.L D0,A0
- MOVE.L SigNow,D0
- ADD.L #SigElSize,D0
- MOVE.L D0,SigNow ;save new position
- CMP.L SigEnd,D0 ;have we reached the end?
- BNE.S catchit ;no, proceed
-
- ;signals, we use 'em ourselves
- MOVE.L SigNow,SigEnd ;restore old ending offset
- MOVE.L #SigElSize,D0
- SUB.L D0,SigNow ;ditto for current position
- MOVE.W #CatchSigErr,4(A7) ;we'll signal a "couldn't
- ; catch" error
- JSR Signal ;never returns of course
-
- catchit
- ADD.L D0,A0 ;point to new entry
- FailuresEntry ;A0=pointer to FailInfo block,A1=handler address,
- ; D1=flag showing how we entered, D2=return address
- MOVE.L A0,D0 ;save FailInfo record address
-
- MOVE.W D1,whatSignals(A0) ;remember what’s catching (-1=CatchFailures,
- ; 0=CatchCFailures, 1=CatchSignal)
- BLE.S @1 ;can’t use frame to clean up if they’ll call Success
-
- CMP.L #SigBigA6,A6 ;are we at the outer level?
- BEQ.S @1 ;yes, no frame, no cleanup needed
- MOVE.L FrameRet(A6),SigFRet(A0) ;save old frame return
- ; address
- LEA SiggyPop,A0
- MOVE.L A0,FrameRet(A6) ;set cleanup code address
- MOVE.L D0,A0 ;restore FailInfo record address
- @1
- MOVEM.L A2-A7/D3-D7,(A0) ;save all registers first (note that the saved
- ; stack points to the function result for CatchSignal)
- ADD #nSavedRegs*4,A0 ;advance pointer by # bytes regs
-
- CLR.W (A0)+ ;clear error field
- CLR.L (A0)+ ;clear message field
- CLR.L (A0)+ ;clear A6 link
-
- TST.W D1 ;was CatchFailures used?
- BPL.S @2 ;no, CatchCFailures or CatchSignal; skip
- MOVE.L A6,-4(A0) ;save the A6Link
- @2
- MOVE.L A1,(A0)+ ;save the handler ptr
-
- MOVE.L gTopHandler(A5),(A0)+ ;Link the FailInfo into the list
- MOVE.L D0,gTopHandler(A5)
- MOVE.L D2,(A0)+ ;remember the caller's PC for MA debugging
-
- MOVE.L D2,A0 ;get return address
- JMP (A0)
- Tail 'CATCHSIG'
-
- ALIGN
- SiggyPop
- Head
- MOVE.L D0,-(A7) ;save D0 in case we’re returning from a c function
-
- MOVE.L SigPointer,A0
- MOVE.L A0,D0 ;to set CCR
- BEQ SigDeath ;nil pointer means trouble
- MOVE.L SigNow,D0 ;grab table offset to entry
- BMI SigDeath ;if no entries then give up
- ADD.L D0,A0 ;point to current element
-
- MOVE.L SigFRet(A0),-(A7) ;push proc's real return address
- BSR SiggyPop2 ;pop element and call Success to pop handler
- MOVE.L (A7)+,A1 ;get proc’s return address
- MOVE.L (A7)+,D0 ;get back D0 in case we’re returning from c
- JMP (A1)
- Tail 'SIGGYPOP'
-
- ENDP
-
-
-
-
- If &UsingMacApp Then
- Seg 'MAMain'
- EndIf
- FreeSignal PROC EXPORT ;PROCEDURE FreeSignal;
- IMPORT SigDeath,Success
- IMPORT gTopHandler:Data
- EXPORT SiggyPop2
- WITH SigGlobals
-
- Head
- MOVE.L gTopHandler(A5),A0 ;point to FailInfo record
- MOVE.L A0,D0 ;to set CCR
- BEQ.S SigDeath
-
- TST.W whatSignals(A0) ;was CatchSignal used?
- BLE.S SiggyPop3 ;no, call Success and return
-
- MOVE.L SigNow,D0 ;grab table offset to entry
-
- MOVE.L SigA6(A0),A1 ;get A6 at point of CatchSignal
- CMP.L #SigBigA6,A1 ;is it at the outer level?
- BEQ.S SiggyPop2 ;yes, don't jam the address if no frame
- MOVE.L SigFRet(A0),FrameRet(A1) ;"pop" cleanup code
- SiggyPop2
- SUB.L #SigElSize,D0
- MOVE.L D0,SigNow ;"pop" the entry
- SiggyPop3
- MOVE.L A0,-(A7) ;push address for Success (FailInfo’s)
- JSR Success ;let MacApp remove FailInfo from list; return
- RTS
- Tail 'FREESIGN'
-
- ENDP
-
- If &UsingMacApp Then
- Seg 'MAMain'
- EndIf
- SignalMessage PROC EXPORT ;PROCEDURE SignalMessage(code: INTEGER; message: LONGINT);
- IMPORT SignalEntry
- WITH SigGlobals
-
- Head
- MOVE.L (A7)+,A1 ;get return address
- MOVE.L (A7)+,D0 ;get message
- BRA.S SignalEntry
- Tail 'SIGNALME'
-
- Signal PROC EXPORT ;PROCEDURE Signal(code:INTEGER);
- IMPORT Failure
- EXPORT SigDeath,SignalEntry
- code EQU 4
- WITH SigGlobals
-
- Head
- MOVE.L (A7)+,A1 ;get return address
- CLR.L D0 ;message := 0
- SignalEntry
- MOVE.W (A7)+,D1 ;get code
- BNE.S @0 ;process the signal if code is non-zero
- JMP (A1) ;return to caller (code was 0)
- @0
- MOVE.W D1,-(A7) ;push code
- MOVE.L D0,-(A7) ;push message
- JSR Failure ;this will pop the handler and call SignalFailure
- SigDeath
- _Debugger ;wasn’t supposed to come back…
- Tail 'SIGNAL '
-
- ENDP
-
- If &UsingMacApp Then
- Seg 'MAMain'
- EndIf
- DoFailure PROC EXPORT ;PROCEDURE DoFailure(VAR fi: FailInfo);
- IMPORT Failure
- fi EQU 4
-
- Head
- BSR FreeSignal ;pop this guy off (but the record is still valid)
-
- MOVE.L fi(A7),A0 ;get FailInfo record
-
- MOVEM.L (A0),A2-A7/D3-D7 ;restore regs (can't use A7 anymore)
- ADD #nSavedRegs*4,A0 ;advance pointer
-
- MOVE.W (A0)+,D0 ;get error
-
- TST.W whatSignals-nSavedRegs*4-2(A0) ;was CatchSignal used?
- BGT.S @2 ;yes, skip
-
- MOVE.L (A0)+,D1 ;get message
- MOVEM.L D0/D1,-(SP) ;save error and message for later use
-
- MOVE.W D0,-(SP)
- MOVE.L D1,-(SP) ;parameters to failure handler
-
- MOVE.L (A0)+,D0 ;check the A6Link
- BEQ.S @1 ;if NIL then don't pass it
- MOVE.L D0,-(SP) ;else do pass it
- @1
- MOVE.L (A0)+,A0 ;get address of failure handler
-
- JSR (A0) ;call failure handler
-
- MOVEM.L (SP)+,D0/D1 ;get error & message back
- MOVE.W D0,-(SP)
- MOVE.L D1,-(SP) ;parameters to Failure
- JSR Failure
- _Debugger ;not supposed to fail to fail
-
- @2
- MOVE.W D0,(A7) ;set CatchSignal function result
- MOVE.L 8(A0),A0 ;address of the failure handler-skip msg. & A6 link
- JMP (A0) ;go to point of CatchSignal
- Tail 'DOFAILUR'
-
- ENDP
-
-
- END
-